#lang scribble/base

@(require "shared.rkt")

@(define-syntax-rule
  (good form code ...)
  (racketmod #:file (tt @;{"good"}"好的") racket form code ...))

@title{@;{Textual Matters}文本问题}

@;{Simple textual conventions help eyes find pieces of code quickly. Here are
some of those that are easy to check---some automatically and some
manually. If you find yourself editing a file that violates some of the
constraints below, edit it into the proper
shape.}简单的文本约定有助于视线快速找到代码片段。这里有一些是很容易检查——一些自动和一些手动。如果编辑的文件违反了下面的某些约束，请将其编辑为正确的形态。 @margin-note{@bold{@;{Warning}警告}@;{: On rare occasion a unit test may depend
on the indentation of a file. This is extremely rare and must be noted at
the top so that readers do not accidentally re-indent the file.}：很少情况下，单元测试可能依赖于文件的缩进。这种情况极为罕见，必须在顶部注明，以免读者意外地重新缩进文件。}


@; -----------------------------------------------------------------------------
@section{@;{Where to Put Parentheses}插入括号的位置}

Racket isn't C. Put all closing parentheses on one line, the last line of
your code.
Racket不是C。把所有的右括号放在一行，代码的最后一行。

@compare[
 @racketmod[#:file
 @tt{@;{good}好的}
 racket
@;%
 (define (conversion f)
   (* 5/9 (- f 32)))
]
 @filebox[@tt{@;{really bad}真的很差}
 @codeblock{#lang racket
 (define (conversion f)
   (* 5/9 (- f 32)
     )
   )
 }]
]

@;{You are allowed to place all closing parenthesis on a line by itself at the
end of long sequences, be those definitions or pieces of data.}
允许将所有右括号单独放在一行的长序列末尾，无论是这些定义还是数据片段。

@compare[
 @filebox[@tt{@;{acceptable}可接受}
 @codeblock{#lang racket
 (define modes
   '(edit
     help
     debug
     test
     trace
     step
     ))
 }]
 @filebox[@tt{@;{also acceptable}也可接受}
 @codeblock{#lang racket
 (define turn%
   (class object%
     (init-field state)

     (super-new)

     (define/public (place where tile)
       (send state where tile))

     (define/public (is-placable? place)
       (send state legal? place))
     ))
 }]
]
 @;{Doing so is most useful when you expect to add, delete, or swap items in
 such sequences.}
当你希望在这样的序列中添加、删除或交换项时，这样做非常有用。

@; -----------------------------------------------------------------------------
@section{@;{Indentation}缩进}

@;{DrRacket indents code and it is the only tool that everyone in PLT agrees
 on. So use DrRacket's indentation style. Here is what this means.}DrRacket缩进代码，它是PLT中每个人都同意的唯一工具。所以使用DrRacket的缩进样式。这就是它的意思。
 @nested[#:style 'inset]{
 @;{For every file in the repository, DrRacket's "indent all" functions leaves
 the file alone.}对于存储库中的每个文件，DrRacket的“全部缩进”函数将文件单独保存。}

@;{If you prefer to use some other editor (emacs, vi/m, etc), program it so
that it follows DrRacket's indentation style.}
如果你喜欢使用其他编辑器（emacs、vi/m等），请对其进行编程，使其遵循DrRacket的缩进样式。


@;{Examples:}
示例：

@compare[
         @racketmod[#:file
                    @tt{@;{good}好的}
                    racket

		    (code:comment #, @t{@;{drracket style}drracket样式})
                    (if (positive? (rocket-x r))
                        (launch r)
                        (redirect (- x)))
                                         ]

          @racketmod[#:file
                     @tt{@;{bad}差的}
                     racket

		     (code:comment #, @t{.el emacs-file if})
                     (if (positive? (rocket-x r))
                         (launch r)
                       (redirect (- x)))
 ]
]

@;{@bold{Caveat 1}: Until language specifications come with fixed indentation
rules, we need to use the @emph{default} settings of DrRacket's indentation
for this rule to make sense. If you add new constructs, say a for loop,
please contact Robby for advice on how to add a default setting for the
indentation functionality. If you add entire languages, say something on
the order of Typed Racket, see
@secref[#:doc '(lib "scribblings/tools/tools.scrbl") "lang-languages-customization"]
for how to implement tabbing.}
@bold{注意1}：在语言规范中包含固定的缩进规则之前，我们需要使用DrRacket缩进的@emph{默认}设置才能使该规则有意义。如果你添加了新的构造，比如for循环，请联系Robby，以获得有关如何为缩进功能添加默认设置的建议。如果你添加了整个语言，请按Typed Racket的顺序说出一些内容，有关如何实现制表符的信息，请参阅@secref[#:doc '(lib "scribblings/tools/tools.scrbl") "lang-languages-customization"]。

@;{@bold{Caveat 2}: This rule does not apply to scribble code.}
@bold{警告2}：此规则不适用于scribble代码。

@; -----------------------------------------------------------------------------
@section{@;{Tabs}制表符}

@;{Do not use tab characters in your code.  Tabs make it hard to use textual
 tools like git or diff effectively.  To disable tabs,}
不要在代码中使用制表符。制表符很难有效地使用git或diff等文本工具。要禁用制表符，
@itemlist[
@item{@;{in DrRacket: you are all set. It doesn't insert tabs.}
 在DrRacket：你已经准备好了。它不插入标签。}
@item{@;{in Emacs: add @tt{(setq indent-tabs-mode nil)} to your emacs initialization file.}
 在Emacs：添加@tt{(setq indent-tabs-mode nil)}到Emacs初始化文件。}
@item{@;{in vi: @tt{:set expandtab}1.}
 在vi：@tt{:set expandtab}1。}
]

@; -----------------------------------------------------------------------------
@section{@;{Line Width}行宽}

@;{A line in a Racket file is at most @LINEWIDTH[] characters wide.}
Racket文件中的一行最宽不超过@LINEWIDTH[]个字符。

@;{If you prefer a narrower width than @LINEWIDTH[], and if you stick to this
width ``religiously,'' add a note to the top of the file---right below the
purpose statement---that nobody should violate your file-local rule.}
如果你喜欢比@LINEWIDTH[]窄的宽度，并且你“虔诚地”坚持使用此宽度，请在文件顶部的用途说明下面添加一个注释，说明任何人都不应违反你的文件本地规则。

@;{This number is a compromise. People used to recommend a line width of 80 or
72 column. The number is a historical artifact. It is also a good number
for several different reasons: printing code in text mode, displaying code
at reasonable font sizes, comparing several different pieces of code on a
monitor, and possibly more. So age doesn't make it incorrect. We regularly
read code on monitors that accommodate close to 250 columns, and on
occasion, our monitors are even wider. It is time to allow for somewhat
more width in exchange for meaningful identifiers.}
这个数字是一个折衷方案。以前人们推荐的行宽是80或72列。这个数字是历史文物。它也是一个很好的数字，有几个不同的原因：在文本模式下打印代码，以合理的字体大小显示代码，在监视器上比较多个不同的代码片段，甚至更多。所以时代不会让它不正确。我们经常在可容纳近250列的显示器上读代码，有时，我们的显示器甚至更宽。现在是时候允许更多的宽度来交换有意义的标识符了。

@;{So, when you create a file, add a line with @litchar{;; } followed by ctrl-U 99 and
@litchar{-}. When you separate "sections" of code in a file, insert the same line.
These lines help both writers and readers to orient themselves in a file.
In scribble use @litchar|{@; }| as the prefix.}
因此，在创建文件时，添加一行@litchar{;; }后跟ctrl-U 99和@litchar{-}。当在文件中分离代码的“小节”时，请插入同一行。这些行帮助作者和读者在文件中定位自己。在scribble中使用@litchar|{@; }|作为前缀。

@; -----------------------------------------------------------------------------
@section{@;{Line Breaks}换行符}

@;{Next to indentation, proper line breaks are critical.}
仅次于缩进，适当的换行是关键。

@;{For an @scheme[if] expression, put each alternative on a separate line.}
对于@scheme[if]表达式，请将每个替代项放在单独的行上。

@compare[
@racketmod[#:file
@tt{@;{good}好的}
racket

(if (positive? x)
    (launch r)
    (redirect (- x)))
]

@racketmod[#:file
@tt{@;{bad}差的}
racket

(if (positive? x) (launch r)
    (redirect (- x)))
]
]

@;{It is acceptable to have an entire @racket[if] expressions on one line if
it fits within the specified line width (@LINEWIDTH[]):}
如果一行上有一个完整的@racket[if]表达式，并且它符合指定的行宽度（@LINEWIDTH[]），则可以接受：

@codebox[
@racketmod[#:file
@tt{@;{also good}也还好}
racket

(if (positive? x) x (- x))
]
]

@;{Each definition and each local definition deserves at least one line.}
每个定义和每个局部定义至少应该有一行。

@compare[
@racketmod[#:file
@tt{@;{good}好的}
racket

(define (launch x)
  (define w 9)
  (define h 33)
  ...)
]

@racketmod[#:file
@tt{@;{bad}差的}
racket

(define (launch x)
  (define w 9) (define h 33)
  ...)
]
]

@;{All of the arguments to a function belong on a single line unless the line
becomes too long, in which case you want to put each argument expression on
its own line}
函数的所有参数都属于一行，除非该行太长，在这种情况下，你会希望将每个参数表达式放在自己的行上

@compare[
@racketmod[#:file
@tt{@;{good}好的}
racket

(place-image img 10 10 background)

(code:comment #, @t{and})

(above img
       (- width  hdelta)
       (- height vdelta)
       bg)
]

@racketmod[#:file
@tt{@;{bad}差的}
racket

(above ufo
       10 v-delta bg)

]]

@;{Here is an exception:}
这里有一个例外：
@codebox[
@racketmod[#:file
@tt{@;{good}好的}
racket

(overlay/offset (rectangle 100 10 "solid" "blue")
                10 10
                (rectangle 10 100 "solid" "red"))
]]
 @;{In this case, the two arguments on line 2 are both conceptually
 related and short.}
在这种情况下，第2行的两个参数在概念上都是相关的，而且都很短。

@; -----------------------------------------------------------------------------
@section[#:tag "names"]{@;{Names}命名}

@;{Use meaningful names. The Lisp convention is to use full English words
separated by dashes. Racket code benefits from the same convention.}
使用有意义的名称。Lisp的惯例是使用用破折号分隔的完整英语单词。Racket代码从相同的惯例中受益。

@compare[
@;%
@(begin
#reader scribble/comment-reader
[racketmod #:file
@tt{@;{good}好的}
racket

render-game-state

send-message-to-client

traverse-forest
])

@; -----------------------------------------------------------------------------
@;%
@(begin
#reader scribble/comment-reader
[racketmod #:file
@tt{@;{bad}差的}
racket

rndr-st

sendMessageToClient

traverse_forest
])
]
@;
 @;{Note that _ (the underline character) is also classified as bad
 Racketeering within names. It is an acceptable placeholder in syntax
 patterns, match patterns, and parameters that don't matter.}
注意 _（下划线字符）也被归类为名称中的差的Racket成员。它是语法模式、匹配模式和无关紧要的参数中可接受的占位符。

@;{Another widely used convention is to @emph{prefix} a function name with the data
 type of the main argument. This convention generalizes the selector-style
 naming scheme of @racket[struct].}
另一个广泛使用的约定是用主参数的数据类型@emph{前缀（prefix）}函数名。此约定泛化了@racket[struct]的选择器样式命名方案。
@codebox[
@(begin
#reader scribble/comment-reader
[racketmod #:file
@tt{@;{good}好的}
racket

board-free-spaces      board-closed-spaces    board-serialize
])]
 @;{In contrast, variables use a @emph{suffix} that indicates their type:}
相反，变量使用的@emph{后缀（suffix）}表示其类型：
@codebox[
@(begin
#reader scribble/comment-reader
[racketmod #:file
@tt{@;{good}好的}
racket

(define (win-or-lose? game-state)
  (define position-nat-nat (game-state-position game-state))
  (define health-level-nat (game-state-health game-state))
  (define name-string      (game-state-name game-state))
  (define name-symbol      (string->symbol name-string))
  ...)
])]
 @;{The convention is particularly helpful when the same piece of data shows
 up in different guises, say, symbols and strings.}
当同一段数据以不同的形式（比如符号和字符串）显示时，该约定特别有用。

@;{Names are bad if they heavily depend on knowledge about the context of the
 code. It prevents readers from understanding a piece of functionality at
 an approximate level without also reading large chunks of the surrounding
 and code.}
如果名称在很大程度上依赖于有关代码上下文的知识，那么名称就不好。它防止读者在不阅读大量周围内容和代码的情况下，以近似的水平理解一个功能。

@;{Finally, in addition to regular alphanumeric characters, Racketeers use a
 few special characters by convention, and these characters indicate
 something about the name:}
最后，除了普通的字母数字字符外，Racket成员还按照惯例使用了一些特殊字符，这些字符表明了该名称的某些内容：

@row-table[
 @row[@;{Character}字符 @;{Kind}种类 @;{Example}示例]
 @row[?    @;{"predicates and boolean-valued functions"}"判断和布尔值函数" boolean?]
 @row[!    @;{"setters and field mutators"}"设置器和字段变换器"              set!]
 @row[%    @;{"classes"}"类"                                 game-state%]
 @row[<%>  @;{"interfaces"}"接口"                              dc<%>]
 @row[^    @;{"unit signatures"}"单元签名"                         game-context^]
 @row["@"  @;{"units"}"单元"                                   testing-context@]
 @row["#%" @;{"kernel identifiers"}"内核标识符"                      #%app]
 @row["/"  @;{"\"with\" (a preposition)"}"“with”（介词）"                call/cc]
]
 @margin-note*{@;{Identifiers with the @litchar{#%} prefix are mostly used in modules that
 define new languages.}前缀为@litchar{#%}的标识符主要用于定义新语言的模块中。}  @;{The use of @litchar{#%} to prefix names from the kernel
 language warns readers that these identifiers are extremely special and
 they need to watch out for subtleties. No other identifiers start with
 @litchar{#} and, in particular, all tokens starting with @litchar{#:} are keywords.}
使用@litchar{#%}作为内核语言名称的前缀会警告读者，这些标识符非常特殊，需要注意其中的微妙之处。没有其他标识符以@litchar{#}开头，尤其是以@litchar{#:}开头的所有标记都是关键字。

@; -----------------------------------------------------------------------------
@section{@;{Graphical Syntax}图形语法}

@;{Do not use graphical syntax (comment boxes, XML boxes, etc).}
不要使用图形语法（注释框、XML框等）。

@;{The use of graphical syntax makes it impossible to read files in
alternative editors. It also messes up some revision control systems.
When we figure out how to save such files in an editor-compatible way, we
may relax this constraint.}
图形语法的使用使得在其他编辑器中无法读取文件。它还扰乱了一些修订控制系统。当我们知道如何以与编辑器兼容的方式保存这些文件时，我们可以放松这个约束。

@section{@;{Spaces}空格}

@;{Don't pollute your code with spaces at the end of lines.}
不要用行尾的空格来污染代码。

@;{If you find yourself breaking long blocks of code with blank lines to aid
readability, consider refactoring your program to introduce auxiliary
functions so that you can shorten these long blocks of code. If nothing
else helps, consider using (potentially) empty comment lines.}
如果你发现自己用空行分隔长代码块以提高可读性，请考虑重构程序以引入辅助函数，以便缩短这些长代码块。如果没有其他帮助，请考虑使用（潜在的）空注释行。

@; -----------------------------------------------------------------------------
@section{@;{End of File}文件结尾}

@;{End files with a newline.}
用换行符结束文件。
